package com.jsbs.iam.common.core.aop;


import com.jsbs.iam.common.core.constant.Constants;
import com.jsbs.iam.common.core.entity.LogWeb;
import com.jsbs.iam.common.core.mapper.LogWebMapper;
import com.jsbs.iam.common.core.utils.Json;
import com.jsbs.iam.common.core.utils.RequestUtils;
import com.jsbs.iam.common.core.utils.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.time.LocalDateTime;
import java.util.Map;

@Aspect
@Component
public class LogDbAop {
    // mysql text类型最长限制
    public static final int MYSQL_TEXT_MAX_LENGTH = 65535/3;
    private static final Logger LOGGER = LoggerFactory.getLogger(LogDbAop.class);

    @Autowired
    LogWebMapper logWebMapper;

    @Pointcut("@annotation(LogDb)")
    private void pointcut(){}

    @Around("pointcut()")
    public Object advice(ProceedingJoinPoint joinPoint) throws Throwable {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        //判断是否是json请求
        boolean isJsonReq = RequestUtils.isJsonRequest(request);
        long logId;
        if (isJsonReq) {
            logId = logJsonReq(request, joinPoint);
        } else {
            logId = logFormReq(request);
        }

        Object ret = joinPoint.proceed();
        String rspContent = Json.toJsonString(ret);
        LOGGER.info(String.format("请求接口:%s,响应结果:%s", request.getRequestURI(), rspContent));
        updateLogWeb(logId, rspContent);
        return ret;
    }

    private int updateLogWeb(long logId, String rspContent) {
        // 因为中文不止占一个字符，rspContent 长度最大值为 MYSQL_TEXT_MAX_LENGTH / 3
        if (StringUtils.isNotEmpty(rspContent) && rspContent.length() > MYSQL_TEXT_MAX_LENGTH / 3) {
            rspContent = rspContent.substring(0, MYSQL_TEXT_MAX_LENGTH / 3);
        }
        return logWebMapper.updateLogWeb(logId, rspContent, LocalDateTime.now());
    }

    long logJsonReq(HttpServletRequest request, ProceedingJoinPoint joinPoint){
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        for(int i = 0; i < method.getParameters().length; i++) {
            Parameter parameter = method.getParameters()[i];
            if (parameter.isAnnotationPresent(RequestBody.class)) {
                //获取参数的值
                Object reqBody = joinPoint.getArgs()[i];
                if (reqBody == null) {
                    break;
                }
                String uri = request.getRequestURI();
                String reqParam = Json.toJsonString(reqBody);
                LOGGER.info(String.format("请求接口:%s,请求参数:%s", uri, reqParam));
                return insertLongWb(uri, reqParam, request);
            }
        }
        String uri = request.getRequestURI();
        LOGGER.info(String.format("请求接口:%s", uri));
        return insertLongWb(uri, null, request);
    }

    private long insertLongWb(String uri, String reqParam, HttpServletRequest request) {
        LogWeb logWeb = buildLogWeb(uri, reqParam, request);
        logWebMapper.insertLogWeb(logWeb);
        return logWeb.getId();
    }

    long logFormReq(HttpServletRequest request){
        Map<String, String[]> parameterMap = request.getParameterMap();
        if(CollectionUtils.isEmpty(parameterMap)){
            String uri = request.getRequestURI();
            LOGGER.info(String.format("请求接口:%s", uri));
            return insertLongWb(uri, null, request);
        }
        String uri = request.getRequestURI();
        String reqParam = Json.toJsonString(parameterMap);
        LOGGER.info(String.format("请求接口:%s,请求参数:%s", uri, reqParam));
        return insertLongWb(uri, reqParam, request);
    }

    private LogWeb buildLogWeb(String uri, String reqParam, HttpServletRequest request){
        LogWeb entity = new LogWeb();
        entity.setUserPhone(request.getHeader(Constants.PHONE));
        entity.setUserName(request.getHeader(Constants.NAME));
        entity.setReqTime(LocalDateTime.now());
        entity.setReqUri(uri);
        if (StringUtils.isNotEmpty(reqParam) && reqParam.length() > MYSQL_TEXT_MAX_LENGTH) {
            reqParam = reqParam.substring(0, MYSQL_TEXT_MAX_LENGTH);
        }
        entity.setReqParam(reqParam);
        return entity;
    }
}
